package znet

import (
	"fmt"
	"net"
	"zinx/utils"
	"zinx/ziface"
)

// iServer的接口实现，定义一个Server的服务器模块
type Server struct {
	//服务器的名称
	Name string
	//服务器绑定的id版本
	IPVersion string
	//服务器监听的IP
	Ip string
	//服务器监听的端口
	Port int
	//当前的Server添加一个router，server注册的链接对应的处理业务
	// Router ziface.IRouter
	MsgHandler ziface.IMsgHandler
}

// 定义当前客户端链接所绑定的Handler api(目前这个handler是写死的，以后优化应该由用户自定义)
//func CallBackToClient(conn *net.TCPConn, data []byte, cnt int) error {
//	//回显的业务
//	fmt.Println("CallBackToClient start.......")
//	if _, err := conn.Write(data[:cnt]); err != nil {
//		fmt.Println("Write err", err)
//		return err
//	}
//	return nil
//}

// 启动服务器
func (s *Server) Start() {
	fmt.Printf("[START] Server name: %s,listenner at IP: %s, Port %d is starting\n", s.Name, s.Ip, s.Port)
	go func() {
		//1、获取一个TCP的Addr
		addr, err := net.ResolveTCPAddr(s.IPVersion, fmt.Sprintf("%s:%d", s.Ip, s.Port))
		if err != nil {
			fmt.Println("resolve tcp addr error", err)
			return
		}
		//2、监听服务器的地址
		listener, err := net.ListenTCP(s.IPVersion, addr)
		if err != nil {
			fmt.Println("listen", s.IPVersion, "err", err)
			return
		}
		fmt.Println("start Zinx server succ, ", s.Name, " succ Listennering...")
		var cid uint32
		cid = 0

		//3、阻塞的等待客户端链接，处理客户端链接业务
		for {
			conn, err := listener.AcceptTCP()
			if err != nil {
				fmt.Println("Accept err", err)
				continue
			}

			//将处理新链接的业务和conn进行绑定 得到我们的链接模块
			dealConn := NewConnection(conn, cid, s.MsgHandler)
			cid++

			//启动当前的链接业务
			go dealConn.Start()
		}
	}()
}

// 停止服务器
func (s *Server) Stop() {
	//TODO 将服务器的资源、状态或者一些已经开辟链接信息 进行停止或者回收
}

// 运行服务器
func (s *Server) Serve() {
	//启动server的服务功能
	s.Start()
	//TODO 做一些启动服务之后的额外业务
	//阻塞状态
	select {}
}

// 路由功能：给当前的服务注册一个路由方法，供客户端的链接处理是有
func (s *Server) AddRouter(msgId uint32, router ziface.IRouter) {
	s.MsgHandler.AddRouter(msgId, router)
	fmt.Println("Add Router Success!")
}

func NewServer(name string) ziface.IServer {
	return &Server{
		Name:      utils.GlobalObject.Name,
		IPVersion: "tcp4",
		Ip:        utils.GlobalObject.Host,
		Port:      utils.GlobalObject.TcpPort,
		// Router:    nil,
		MsgHandler: NewMsgHandler(),
	}
}
